﻿using Inspire.Classes.Business;
using Inspire.Interfaces;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace Inspire.Entities
{
    public partial class Resource : IDataErrorInfo, IValidation
    {
        private ResourceBusiness _resourceBusiness;

        #region IDataErrorInfo Members

        /// <summary>
        /// Stores message messages mapped to the name of the property to which they belong.
        /// </summary>
        private Dictionary<string, string> _errors = new Dictionary<string, string>();

        /// <summary>
        /// General Error message regarding this object.
        /// 
        /// This is part of the IDataErrorInfo implementation.
        /// </summary>
        public string Error
        {
            get 
            {
                return String.Empty;
            }
        }

        /// <summary>
        /// Indexer for properties of this object.
        /// 
        /// This is part of the IDataErrorInfo implementation.
        /// </summary>
        /// <param name="columnName">(string) The property to check for errors.</param>
        /// <returns>(string) If an there is an message with the specified property, the message message for that message.</returns>
        public string this[string columnName]
        {
            get 
            {
                if (_errors.ContainsKey(columnName))
                {
                    return this._errors[columnName];
                }
                return String.Empty;
            }
        }

        #endregion

        /// <summary>
        /// Constructor.
        /// </summary>
        public Resource()
        {
            // Get a reference to ResourceBusiness
            this._resourceBusiness = ResourceBusiness.GetResourceBusiness();
        }

        #region Partial implementation of Property Event Handlers

        /// <summary>
        /// Event handler for changing of the Authors Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnAuthorsLabelChanging(string value)
        {
            string errorMessage = this.ValidateAuthorsLabel(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("AuthorsLabel")))
                {
                    this._errors.Add("AuthorsLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("AuthorsLabel");
            }
        }

        /// <summary>
        /// Event handler for changing of the Accession Letter property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnAccessionLettersChanging(string value)
        {
            string errorMessage = this.ValidateAccessionLetters(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("AccessionLetters")))
                {
                    this._errors.Add("AccessionLetters", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("AccessionLetters");
            }
        }

        /// <summary>
        /// Event handler for changing of the Checkout Period property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnCheckoutPeriodChanging(int? value)
        {
            string errorMessage = this.ValidateCheckoutPeriod(value);

            // Must check for pre-existing key -- the IntegerUpDown control this is bound to doesn't update the way other controls do
            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("CheckoutPeriod")))
                {
                    this._errors.Add("CheckoutPeriod", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("CheckoutPeriod");
            }
        }

        /// <summary>
        /// Event handler for changing of the Description property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnDescriptionChanging(string value)
        {
            string errorMessage = this.ValidateDescription(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("Description")))
                {
                    this._errors.Add("Description", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("Description");
            }
        }

        /// <summary>
        /// Event handler for changing of the Editor Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnEditorLabelChanging(string value)
        {
 	        string errorMessage = this.ValidateEditorLabel(value);

            if(errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("EditorLabel")))
                {
                    this._errors.Add("EditorLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("EditorLabel");
            }
        }

        /// <summary>
        /// Event handler for changing of the Illustrators Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnIllustratorsLabelChanging(string value)
        {
            string errorMessage = this.ValidateIllustratorsLabel(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("IllustratorsLabel")))
                {
                    this._errors.Add("IllustratorsLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("IllustratorsLabel");
            }
        }

        /// <summary>
        /// Event handler for changing of the Material Description property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnMaterialDescriptionChanging(string value)
        {
            string errorMessage = this.ValidateMaterialDescription(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("MaterialDescription")))
                {
                    this._errors.Add("MaterialDescription", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("MaterialDescription");
            }
        }

        /// <summary>
        /// Event handler for changing of the Name property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnNameChanging(string value)
        {
            string errorMessage = this.ValidateName(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("Name")))
                {
                    this._errors.Add("Name", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("Name");
            }
        }

        /// <summary>
        /// Event handler for changing of the Publisher Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnPublisherLabelChanging(string value)
        {
 	        string errorMessage = this.ValidatePublisherLabel(value);

            if(errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("PublisherLabel")))
                {
                    this._errors.Add("PublisherLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("PublisherLabel");
            }
        }

        /// <summary>
        /// Event handler for changing of the Size Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnSizeLabelChanging(string value)
        {
            string errorMessage = this.ValidateSizeLabel(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("SizeLabel")))
                {
                    this._errors.Add("SizeLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("SizeLabel");
            }
        }

        /// <summary>
        /// Event handler for changing of the Size Suffix property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnSizeSuffixChanging(string value)
        {
            string errorMessage = this.ValidateSizeSuffix(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("SizeSuffix")))
                {
                    this._errors.Add("SizeSuffix", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("SizeSuffix");
            }
        }

        /// <summary>
        /// Event handler for changing of the Subject Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnSubjectLabelChanging(string value)
        {
            string errorMessage = this.ValidateSubjectLabel(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("SubjectLabel")))
                {
                    this._errors.Add("SubjectLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("SubjectLabel");
            }
        }

        /// <summary>
        /// Event handler for chaning of the Volume Label property.
        /// </summary>
        /// <param name="value">The incoming value.</param>
        partial void OnVolumeLabelChanging(string value)
        {
            string errorMessage = this.ValidateVolumeLabel(value);

            if (errorMessage.Length > 0)
            {
                if (!(this._errors.ContainsKey("VolumeLabel")))
                {
                    this._errors.Add("VolumeLabel", errorMessage);
                }
            }
            else
            {
                this._errors.Remove("VolumeLabel");
            }
        }

        #endregion

        #region IValidation members

        /// <summary>
        /// Returns a validation message for the Accession Letter property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateAccessionLetters(string value)
        {
            if (value != null && value.Length > 100)
            {
                return "Accession Letters has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Authors Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateAuthorsLabel(string value)
        {
            if(value != null && value.Length > 100)
            {
                return "Authors Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Checkout Period property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateCheckoutPeriod(int? value)
        {
            if (value == null || value < 1)
            {
                return "Checkout Period cannot be blank and must be greater than 0.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Description property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateDescription(string value)
        {
            if (value != null && value.Length > 300)
            {
                return "Description has a max length of 300 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Editor Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateEditorLabel(string value)
        {
            if(value != null && value.Length > 100)
            {
                return "Editor Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Illustrators Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateIllustratorsLabel(string value)
        {
            if(value != null && value.Length > 100)
            {
                return "Illustrators Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Material Description property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateMaterialDescription(string value)
        {
            if (value != null && value.Length > 300)
            {
                return "Material Description has a max length of 300 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Name property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateName(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Name cannot be blank.";
            }
            else if (value.Length > 100)
            {
                return "Name has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Publisher Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidatePublisherLabel(string value)
        {
            if(value != null && value.Length > 100)
            {
                return "Publisher Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Size Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateSizeLabel(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Size Label cannot be blank.";
            }
            else if (value.Length > 100)
            {
                return "Size Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Size Suffix property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateSizeSuffix(string value)
        {
            if (value == null || value.Trim().Length < 1)
            {
                return "Size Suffix cannot be blank.";
            }
            else if (value.Length > 100)
            {
                return "Size Suffix has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Subject Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateSubjectLabel(string value)
        {
            if (value != null && value.Length > 100)
            {
                return "Subject Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Returns a validation message for the Volume Label property.
        /// </summary>
        /// <param name="value">Value to be validated.</param>
        /// <returns>An error message or an empty string.</returns>
        private string ValidateVolumeLabel(string value)
        {
            if(value != null && value.Length > 100)
            {
                return "Volume Label has a max length of 100 characters.";
            }
            return String.Empty;
        }

        /// <summary>
        /// Validate all fields
        /// </summary>
        /// <returns>True if no errors were found; false, otherwise.</returns>
        public bool Validate()
        {
            // Initialize isValidated to true
            bool isValidated = true;

            // Reset all error messages
            this._errors.Clear();

            #region Validate Fields and add messages to _errors

            // Initialize errorMessage to empty
            string errorMessage = String.Empty;

            // AccessionLetter
            errorMessage = ValidateAccessionLetters(this.AccessionLetters);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("AccessionLetter", errorMessage);
                isValidated = false;
            }

            // Authors Label
            errorMessage = ValidateAuthorsLabel(this.AuthorsLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("AuthorsLabel", errorMessage);
                isValidated = false;
            }

            // CheckoutPeriod
            errorMessage = ValidateCheckoutPeriod(this.CheckoutPeriod);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("CheckoutPeriod", errorMessage);
                isValidated = false;
            }

            // Description
            errorMessage = ValidateDescription(this.Description);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("Description", errorMessage);
                isValidated = false;
            }

            // Editor Label
            errorMessage = ValidateEditorLabel(this.EditorLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("EditorLabel", errorMessage);
                isValidated = false;
            }

            // Illustrators Label
            errorMessage = ValidateIllustratorsLabel(this.IllustratorsLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("IllustratorsLabel", errorMessage);
                isValidated = false;
            }

            // MaterialDescription
            errorMessage = ValidateMaterialDescription(this.MaterialDescription);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("MaterialDescription", errorMessage);
                isValidated = false;
            }

            // Name
            errorMessage = ValidateName(this.Name);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("Name", errorMessage);
                isValidated = false;
            }

            // Publisher Label
            errorMessage = ValidatePublisherLabel(this.PublisherLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("PublisherLabel", errorMessage);
                isValidated = false;
            }

            // SizeLabel
            errorMessage = ValidateSizeLabel(this.SizeLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("SizeLabel", errorMessage);
                isValidated = false;
            }

            // SizeSuffix
            errorMessage = ValidateSizeSuffix(this.SizeSuffix);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("SizeSuffix", errorMessage);
                isValidated = false;
            }

            // SubjectLabel
            errorMessage = ValidateSubjectLabel(this.SubjectLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("SubjectLabel", errorMessage);
                isValidated = false;
            }

            // Volume Label
            errorMessage = ValidateVolumeLabel(this.VolumeLabel);
            if (errorMessage.Length > 0)
            {
                this._errors.Add("VolumeLabel", errorMessage);
                isValidated = false;
            }

            #endregion

            return isValidated;
        }

        /// <summary>
        /// Get all the errors found after the Validate() method is ran
        /// </summary>
        /// <returns>string[] of all message messages</returns>
        public string[] GetAllErrors()
        {
            string[] allErrors = new string[this._errors.Count];

            int counter = 0;
            foreach (KeyValuePair<string, string> nextError in this._errors)
            {
                allErrors[counter] = nextError.Value;
                counter++;
            }

            return allErrors;
        }

        #endregion

        /// <summary>
        /// Provides a Shallow Copy of this object.
        /// </summary>
        /// <returns>A Shallow Copy of the original Resource object.</returns>
        public Resource ShallowCopy()
        {
            return (Resource)this.MemberwiseClone();
        }

        /// <summary>
        /// Resets all values to their default. This method does not commit the changes to the database.
        /// </summary>
        public void Reset()
        {
            // Clear Error Messages of the fields in case setting a field to "" causes an message message to be added.
            // If a message for the field already exists, this will cause a duplicate key message.
            this._errors.Clear();

            // Clear All Fields
            this.Name = "";
            this.Description = "";
            this.CheckoutPeriod = null;
            this.SizeSuffix = "";
            this.SizeLabel = "";
            this.SubjectLabel = "";
            this.MaterialDescription = "";
            this.AccessionLetters = "";
            this.FullSizeImage = new byte[0];
            this.IconSizeImage = new byte[0];
            this.Notes = "";
            this.ParentResourceId = null;
            this.VolumeLabel = "";
            this.AuthorsLabel = "";
            this.IllustratorsLabel = "";
            this.EditorLabel = "";
            this.PublisherLabel = "";

            // Clear Error Messages Regarding the Empty Fields
            this._errors.Clear();
        }
    }
}
